#include "OpenGLWidgetLight.h"
#include<QDebug>
#include<gl/GLU.h>
#include"OpenGLUtil.h"

OpenGLWidgetLight::OpenGLWidgetLight(QWidget* parent) :QOpenGLWidget(parent)
{
	setFocusPolicy(Qt::FocusPolicy::ClickFocus);
}

OpenGLWidgetLight::~OpenGLWidgetLight()
{
}

void OpenGLWidgetLight::setWireFrame(bool wireFrame)
{
	// 在paintGL 函数以外的地方调用OpenGL函数没有意义，最终会被paintGL覆盖。所以必须以如下方式调用OpenGL函数。
	makeCurrent(); // --- 外部调用OpenGL函数前必须以 makeCurrent 函数开始
	if (wireFrame)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
	update();     // --- 外部调用OpenGL函数之后必须以 update 函数更新UI界面
	doneCurrent();// --- 外部调用OpenGL函数之后必须以 doneCurrent 函数结束

}

void OpenGLWidgetLight::initializeGL()
{
	initializeOpenGLFunctions();
	PrintVersion();
	sphere = new ShapeSphere;
	sphere->init(this);

	cube = new ShapeCube({ 0.0f,2.0f,.0f }, 0.5, 0.5, 0.5);
	cube->init(this);

	setLight0(); // 在此处设置的光源位置为固定光源
}

void OpenGLWidgetLight::resizeGL(int w, int h)
{
}

// 设置灯光
void OpenGLWidgetLight::setLight0()
{
	// GL_POSITION:The position is transformed by the modelview matrix when glLight is called: https://docs.gl/gl3/glLight
	// 设置光照 https://learn.microsoft.com/zh-cn/windows/win32/opengl/gllightfv
	// 关于光源位置的设置：在openGL中，光源位置的控制也是通过模型视图矩阵实现的，包括平移、旋转、缩放（因为它会改变法向量，慎用）等: https://www.cnblogs.com/bingcaihuang/archive/2011/01/26/1945619.html
	// glColorMaterial 和 glMaterial 的区别: https://blog.csdn.net/iMatt/article/details/107188243
	// The glColorMaterial function specifies which material parameters track the current color: https://learn.microsoft.com/en-us/windows/win32/opengl/glcolormaterial
	// 模型顶点必须指定法向：OpenGL光照机制是通过计算物体表面法向与入射光线的夹角来确定表面的亮度。故若传入的模型没有指定法向，则最终结果会变得一片漆黑；若法向有问题，最终结果也会莫名其妙。 https://blog.csdn.net/linuxheik/article/details/77248450
	// 当需要改变场景中大部分方面的单个材质时，最好调用glColorMaterial(),当修改不只一个材质参数，最好调用glMaterial*()，这是目前我体会到唯一的使用功能上的不同点吧。https://blog.csdn.net/kalongkaya/article/details/46708331
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);                                    // 启用光源总开关
	glEnable(GL_LIGHT0);                                      // 启用 Light0
	GLfloat light_ambient[] = { 0,0,0,1 };
	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);          // RGBA 模式下环境光 默认：{ 0,0,0,1 }
	GLfloat light_diffuse[] = { 1, 1, 1, 1 };
	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);          // RGBA 模式下漫反射 默认： {1, 1, 1, 1}
	GLfloat light_specular[] = { 1,1,1,1 };
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);        // RGBA 模式下镜面反射 默认：{1,1,1,1}
	GLfloat lightPos[] = { 1,0,0,1 };
	glLightfv(GL_LIGHT0, GL_POSITION, lightPos);              // 点光源位置 为x轴正方向， 默认{0,0,1}
	GLfloat lightDirect[] = { 0,0,-1 };
	glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightDirect);     // 点光源方向 默认{0,0,-1.0}
	glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 0);                 // 点光源聚光指数 默认：0
	glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180);                 // 点光源截止角 默认：180.0 ，设置范围【0~90或180】
	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0);        // 常数衰减因子，默认 1.0
	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0);            // 线性衰减因子，0.0
	glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0);         // 平方衰减因子，0.0
	glEnable(GL_COLOR_MATERIAL);
}

// 设置灯光1
void OpenGLWidgetLight::setLight1()
{
	// 设置光照
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT1);
	GLfloat lightPos[] = { -2,0,0,1 };
	glLightfv(GL_LIGHT1, GL_POSITION, lightPos);
	glEnable(GL_COLOR_MATERIAL);
}

// 设置灯光2
void OpenGLWidgetLight::setLight2()
{
	// 设置光照
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT2);
	GLfloat lightPos[] = { 0,0,2,1 };
	glLightfv(GL_LIGHT2, GL_POSITION, lightPos);
	glEnable(GL_COLOR_MATERIAL);
}

void OpenGLWidgetLight::setMoveLight() // 设置运动光源
{
	//glMatrixMode(GL_MODELVIEW);
	//glPushMatrix();
	//glRotated(m_rotate.x(), 1, 0, 0);
	//glRotated(m_rotate.y(), 0, 1, 0);
	//glScaled(m_scale, m_scale, m_scale);

	GLfloat lightPos[] = { -1.0,0.0,0.0,1 };
	glColor3f(1.0,1.0,1.0);
	glPointSize(10);
	glBegin(GL_POINTS);
	glNormal3f(0,0,1);
	glVertex3f(lightPos[0] , lightPos[1], lightPos[2]-0.01);  // 显示光源位置为一个白色的点
	glEnd();

	glLightfv(GL_LIGHT0, GL_POSITION, lightPos);              // 点光源位置 默认{0,0,1}
	//glPopMatrix();
}

void OpenGLWidgetLight::paintGL()
{
	qDebug() << "paintGL";
	PrintGLSetting();
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);
	
	//// 创建透视效果视图      
	glMatrixMode(GL_PROJECTION);
	//glPushMatrix();
	glLoadIdentity();
	gluPerspective(80.0f, 1.0f, 1.0f, 20.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	setMoveLight();  // 在这里设置光源位置，可以让光源与视角的位置是固定的，而且不会跟随下面的物体旋转和平移

	glRotated(m_rotate.x(), 1, 0, 0);
	glRotated(m_rotate.y(), 0, 1, 0);
	glScaled(m_scale, m_scale, m_scale);
	cube->render();
	sphere->render();
}

void OpenGLWidgetLight::keyPressEvent(QKeyEvent * event)
{
	int d = 2;
	qDebug() << event->key();
	if (event->key() == Qt::Key_Right)
	{
		m_rotate.setY(m_rotate.y() + d);
		update();
	}
	else if (event->key() == Qt::Key_Left)
	{
		m_rotate.setY(m_rotate.y() - d);
		update();
	}
	else if (event->key() == Qt::Key_Up)
	{
		m_rotate.setX(m_rotate.x() - d);
		update();
	}
	else if (event->key() == Qt::Key_Down)
	{
		m_rotate.setX(m_rotate.x() + d);
		update();
	}
	//if()
}

void OpenGLWidgetLight::wheelEvent(QWheelEvent *event) {
	qDebug() << "wheel event";
	qDebug() << event->angleDelta();

	m_scale += event->angleDelta().y() / 1200.0;
	update();
}
